// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Referential.cs" company="Open Trader">
//   Copyright (c) David Denis (david.denis@systemathics.com)
// </copyright>
// <summary>
//   |  Open Trader - The Open Source Systematic Trading Platform
//   |
//   |  This program is free software: you can redistribute it and/or modify
//   |  it under the terms of the GNU General Public License as published by
//   |  the Free Software Foundation, either version 2 of the License, or
//   |  (at your option) any later version.
//   |
//   |  This program is distributed in the hope that it will be useful,
//   |  but WITHOUT ANY WARRANTY; without even the implied warranty of
//   |  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   |  GNU General Public License for more details.
//   |
//   |  You should have received a copy of the GNU General Public License
//   |  along with this program.  If not, see http://www.gnu.org/licenses
//   |
//   |  Up to date informations about Open Trader can be found at :
//   |    http://opentrader.org
//   |    http://opentrader.codeplex.com
//   |
//   |  For professional services, please visit us at :
//   |    http://www.systemathics.com
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Org.OpenTrader.Framework.Forge
{
    #region Using Directives

    using System;
    using System.Linq.Expressions;

    using Org.OpenTrader.Framework.Forge.Enums;
    using Org.OpenTrader.Framework.Forge.Events;
    using Org.OpenTrader.Framework.Forge.Interfaces;

    #endregion

    /// <summary>
    /// The referential.
    /// </summary>
    public class Referential : IReferential
    {
        private static readonly Identity Identity = Identity.Create(System.Reflection.MethodBase.GetCurrentMethod());

        #region Constants and Fields

        /// <summary>
        /// The universe.
        /// </summary>
        private readonly IUniverse universe;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="Referential"/> class.
        /// </summary>
        /// <param name="universe">
        /// The universe.
        /// </param>
        /// <param name="dictionaryProvider">
        /// The dictionary provider.
        /// </param>
        /// <param name="feedProvider">
        /// The feed provider.
        /// </param>
        /// <param name="orderProvider">
        /// The order provider.
        /// </param>
        public Referential(IUniverse universe, IDictionaryProvider dictionaryProvider, IFeedProvider feedProvider, IOrderProvider orderProvider)
        {
            this.DictionaryProvider = dictionaryProvider;
            this.FeedProvider = feedProvider;
            this.OrderProvider = orderProvider;
            this.universe = universe;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets DictionaryProvider.
        /// </summary>
        public IDictionaryProvider DictionaryProvider { get; set; }

        /// <summary>
        /// Gets or sets FeedProvider.
        /// </summary>
        public IFeedProvider FeedProvider { get; set; }

        /// <summary>
        /// Gets Instruments in use in current referential.
        /// </summary>
        public IInstrument[] Instruments
        {
            get
            {
                return this.universe[this];
            }
        }

        /// <summary>
        /// Gets or sets OrderProvider.
        /// </summary>
        public IOrderProvider OrderProvider { get; set; }

        #endregion

        #region Public Methods

        /// <summary>
        /// The to string.
        /// </summary>
        /// <returns>
        /// The to string.
        /// </returns>
        public override string ToString()
        {
            return string.Format("Referential: {0}", this.GetHashCode());
        }

        #endregion

        #region Implemented Interfaces

        #region IReferential

        /// <summary>
        /// The cancel order.
        /// </summary>
        /// <param name="order">
        /// The order.
        /// </param>
        /// <returns>
        /// The cancel order.
        /// </returns>
        public Status CancelOrder(IOrder order)
        {
            // If capability is not enabled, don't do anything
            if (this.OrderProvider == null)
            {
                return Status.Failure(Identity, "CancelOrder: No order provider");
            }

            return this.OrderProvider.CancelOrder(order);
        }

        /// <summary>
        /// The lookup instrument toolkit.
        /// </summary>
        /// <param name="code">
        /// The code.
        /// </param>
        /// <param name="tradingScope">
        /// The tradingScope.
        /// </param>
        /// <returns>
        /// </returns>
        public Status<IInstrument> CreateInstrument(string code, ETradingScope tradingScope)
        {
            return this.universe.CreateInstrument(this, code, tradingScope);
        }

        /// <summary>
        /// The lookup instrument toolkits.
        /// </summary>
        /// <param name="predicate">
        /// The predicate.
        /// </param>
        /// <returns>
        /// </returns>
        public Status<IInstrument[]> CreateInstruments(Expression<Func<IInstrumentStaticData, bool>> predicate)
        {
            return this.universe.CreateInstruments(this, predicate);
        }

        /// <summary>
        /// The create order.
        /// </summary>
        /// <param name="instrumentID">
        /// The instrumentID.
        /// </param>
        /// <param name="type">
        /// The type.
        /// </param>
        /// <param name="way">
        /// The way.
        /// </param>
        /// <param name="price">
        /// The price.
        /// </param>
        /// <param name="quantity">
        /// The quantity.
        /// </param>
        /// <param name="bookingPath">
        /// The bookingPath.
        /// </param>
        /// <param name="handler">
        /// The handler.
        /// </param>
        /// <returns>
        /// </returns>
        public Status<IOrder> CreateOrder(Guid instrumentID, 
                                          EOrderType type, 
                                          EOrderWay way, 
                                          double price, 
                                          int quantity, 
                                          string bookingPath, 
                                          EventHandler<OrderEventArgs> handler)
        {
            // If capability is not enabled, don't do anything
            if (this.OrderProvider == null)
            {
                return Status.Failure<IOrder>(Identity, "CreateOrder: No order provider");
            }

            return this.OrderProvider.CreateOrder(instrumentID, type, way, price, quantity, bookingPath, handler);
        }

        /// <summary>
        /// The modify order.
        /// </summary>
        /// <param name="oldOrder">
        /// The oldOrder.
        /// </param>
        /// <param name="newOrder">
        /// The newOrder.
        /// </param>
        /// <returns>
        /// The modify order.
        /// </returns>
        public Status ModifyOrder(IOrder oldOrder, IOrder newOrder)
        {
            // If capability is not enabled, don't do anything
            if (this.OrderProvider == null)
            {
                return Status.Failure(Identity, "ModifyOrder: No order provider");
            }

            return this.OrderProvider.ModifyOrder(oldOrder, newOrder);
        }

        /// <summary>
        /// The send order.
        /// </summary>
        /// <param name="order">
        /// The order.
        /// </param>
        /// <returns>
        /// The send order.
        /// </returns>
        public Status SendOrder(IOrder order)
        {
            // If capability is not enabled, don't do anything
            if (this.OrderProvider == null)
            {
                return Status.Failure(Identity, "SendOrder: No order provider");
            }

            return this.OrderProvider.SendOrder(order);
        }

        /// <summary>
        /// The shutdown.
        /// </summary>
        public void Shutdown()
        {
            // Destroy instruments
            foreach (var instrument in this.Instruments)
            {
                instrument.Shutdown();
            }
        }

        /// <summary>
        /// The startup.
        /// </summary>
        public void Startup()
        {
        }

        /// <summary>
        /// The subscribe.
        /// </summary>
        /// <param name="instrumentID">
        /// The instrumentID.
        /// </param>
        /// <param name="handler">
        /// The handler.
        /// </param>
        /// <returns>
        /// The subscribe.
        /// </returns>
        public Status Subscribe(Guid instrumentID, EventHandler<FeedEventArgs> handler)
        {
            // If capability is not enabled, don't do anything
            if (this.FeedProvider == null)
            {
                return Status.Failure(Identity, "Subscribe: No feed provider");
            }

            return this.FeedProvider.Subscribe(instrumentID, handler);
        }

        /// <summary>
        /// The unsubscribe.
        /// </summary>
        /// <param name="instrumentID">
        /// The instrumentID.
        /// </param>
        /// <param name="handler">
        /// The handler.
        /// </param>
        /// <returns>
        /// The unsubscribe.
        /// </returns>
        public Status Unsubscribe(Guid instrumentID, EventHandler<FeedEventArgs> handler)
        {
            // If capability is not enabled, don't do anything
            if (this.FeedProvider == null)
            {
                return Status.Failure(Identity, "Unsubscribe: No feed provider");
            }

            return this.FeedProvider.Unsubscribe(instrumentID, handler);
        }

        #endregion

        #endregion
    }
}